package com.wuliang.generate.response.author.controller;

import cn.hutool.captcha.AbstractCaptcha;
import com.wuliang.generate.common.core.response.Result;
import com.wuliang.generate.common.core.response.ResultUtils;
import com.wuliang.generate.common.core.response.ReturnCode;
import com.wuliang.generate.common.core.utils.JsonUtils;
import com.wuliang.generate.common.core.utils.JwtTokenUtils;
import com.wuliang.generate.common.core.utils.RedisUtils;
import com.wuliang.generate.common.core.utils.VerificationCodeUtils;
import com.wuliang.generate.bean.entities.author.AuthorUser;
import com.wuliang.generate.repositories.author.AuthorUserRepository;
import com.wuliang.generate.bean.vo.author.AuthorUserVo;
import com.wuliang.generate.response.author.configs.SecurityAuthenticationProvider;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Optional;

/**
 * @author WuLiang
 */
@RestController
@RequestMapping("/author")
@Api(tags = { "认证相关服务" })
public class SecurityController {

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private AuthorUserRepository authorUserRepository;

    @Autowired
    private SecurityAuthenticationProvider authenticationProvider;

    @PostMapping("/getCodeImg")
    @ApiOperation("获取验证码")
    public Result<Object> getCodeImg(HttpServletRequest request) {
        AbstractCaptcha captcha = VerificationCodeUtils.createCaptcha();
        redisUtils.set(request.getRemoteAddr(), captcha.getCode(), 60 * 5);
        return ResultUtils.success(captcha.getImageBase64Data());
    }

    @PostMapping("/toLogin")
    @ApiOperation("登录")
    public Result<Object> toLogin(@RequestBody AuthorUserVo userVo, HttpServletRequest request) {
        String password = userVo.getUserPassword();
        userVo.setUserPassword(null);
        String rawVerifyCode = String.valueOf(redisUtils.get(request.getRemoteAddr()));
        if ("null".equals(rawVerifyCode)) {
            return ResultUtils.error("验证码已过期", ReturnCode.SYSTEM_EXCEPTION);
        }
        if (!userVo.getVerifyCode().equalsIgnoreCase(rawVerifyCode)) {
            return ResultUtils.error(ReturnCode.ERROR_VERIFICATION_CODE);
        }
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(userVo.getUserUsername(), password);
        authenticationToken.setDetails(userDetailsService.loadUserByUsername(userVo.getUserUsername()));
        Authentication authentication = authenticationProvider.authenticate(authenticationToken);
        if (!authentication.isAuthenticated()) {
            return ResultUtils.error("认证失败错误", ReturnCode.SYSTEM_EXCEPTION);
        }
        redisUtils.del(request.getRemoteAddr());
        SecurityContextHolder.getContext().setAuthentication(authentication);
        Optional<AuthorUser> authorUserOptional = authorUserRepository.findOne(userVo.toSpecification());
        if (!authorUserOptional.isPresent()) {
            return ResultUtils.dataEmptyError();
        }
        Map<String, Object> authorUser = new LinkedHashMap<>(JsonUtils.objectToMap(authorUserOptional.get()));
        authorUser.put("token", JwtTokenUtils.createToken(userVo.getUserUsername(), false));
        return ResultUtils.success(authorUser);
    }

}
